//
//  ParameterValue.swift
//  
//
//  Created by ZhipengZheng on 2020/6/1.
//

import Foundation

public class ParameterValue: NSObject {
    
    public typealias ValuePointer<T> = UnsafeMutablePointer<T>
    public typealias CallBackClosure<T> = (T) -> Void
    public typealias CallBackThrowsClosure<T> = (T) throws -> Void
    public typealias CallBackRBoolClosure = () -> Bool
    
    var key: String
    var miniKey: String
    var type: Any
    var value: Any
    private var internalDescription: String
    public override var description: String {
        return internalDescription
    }
    var onlyUseKey: Bool = false
    
    init(key: String, miniKey: String, type: Any, value: Any, description: String) {
        self.key = key
        self.miniKey = miniKey
        self.type = type
        self.value = value
        self.internalDescription = description
        super.init()
    }
        
    @discardableResult
    /// 解析传入的参数，给指定key对应的value赋值
    func parseValue(withReversed arguments: [String]) throws -> [String] {
        if onlyUseKey {
            guard let action = value as? CallBackRBoolClosure else {
                throw CommandParseError.extend(name: "单独\(key)对应action解析失败", detail: "当前action为\(value)")
            }
            if (action()) {
                return arguments
            } else {
                return []
            }
        }
        
        var tmpArguments:[String] = arguments
        guard let last = tmpArguments.popLast() else {
            throw CommandParseError.nonParameter(detail: "\(key) 需要参数，目前传入为空")
        }
        switch type {
        case is Int.Type:
            guard let lastValue = Int(last) else {
                try throwErrorParameter(type: Int.self, last: last)
                break
            }
            try configureValue(lastValue)
        case is Int8.Type:
            guard let lastValue = Int8(last) else {
                try throwErrorParameter(type: Int8.self, last: last)
                break
            }
            try configureValue(lastValue)
        case is Int16.Type:
            guard let lastValue = Int16(last) else {
                try throwErrorParameter(type: Int16.self, last: last)
                break
            }
            try configureValue(lastValue)
        case is Int32.Type:
            guard let lastValue = Int32(last) else {
                try throwErrorParameter(type: Int32.self, last: last)
                break
            }
            try configureValue(lastValue)
        case is Int64.Type:
            guard let lastValue = Int64(last) else {
                try throwErrorParameter(type: Int64.self, last: last)
                break
            }
            try configureValue(lastValue)
        case is UInt.Type:
            guard let lastValue = UInt(last) else {
                try throwErrorParameter(type: UInt.self, last: last)
                break
            }
            try configureValue(lastValue)
        case is UInt8.Type:
            guard let lastValue = UInt8(last) else {
                try throwErrorParameter(type: UInt8.self, last: last)
                break
            }
            try configureValue(lastValue)
        case is UInt16.Type:
            guard let lastValue = UInt16(last) else {
                try throwErrorParameter(type: UInt16.self, last: last)
                break
            }
            try configureValue(lastValue)
        case is UInt32.Type:
            guard let lastValue = UInt32(last) else {
                try throwErrorParameter(type: UInt32.self, last: last)
                break
            }
            try configureValue(lastValue)
        case is UInt64.Type:
            guard let lastValue = UInt64(last) else {
                try throwErrorParameter(type: UInt64.self, last: last)
                break
            }
            try configureValue(lastValue)
        case is Float.Type:
            guard let lastValue = Float(last) else {
                try throwErrorParameter(type: Float.self, last: last)
                break
            }
            try configureValue(lastValue)
        case is Float80.Type:
            guard let lastValue = Float80(last) else {
                try throwErrorParameter(type: Float80.self, last: last)
                break
            }
            try configureValue(lastValue)
        case is Double.Type:
            guard let lastValue = Double(last) else {
                try throwErrorParameter(type: Double.self, last: last)
                break
            }
            try configureValue(lastValue)
        case is Bool.Type:
            guard let lastValue = Bool(last) else {
                try throwErrorParameter(type: Bool.self, last: last)
                break
            }
            try configureValue(lastValue)
        case is String.Type:
            try configureValue(last)
        default:
            throw CommandParseError.notSupport(detail: "目前类型\(type)， 不支持解析")
        }
        return tmpArguments
    }
    
    private func configureValue<T>(_ lastValue: T) throws {
        if let realValue = value as? ValuePointer<T> {
            realValue.pointee = lastValue
        } else if let realValue = value as? CallBackClosure<T> {
            realValue(lastValue)
        } else if let realValue = value as? CallBackThrowsClosure<T> {
            try realValue(lastValue)
        } else {
            throw CommandParseError.extend(name: "解析参数方法使用失败", detail: "目前解析数据的方法不支持些种类型\(value)")
        }
    }
    
    private func throwErrorParameter(type: Any, last: String) throws {
        throw CommandParseError.errorParameter(detail: "需要参数为 \(type) 类型数据，传入的值转换失败为\(last)")
    }
    
}
